package com.sf.dlb.service;

import com.sf.dlb.bean.NewRquestBean;
import com.sf.dlb.config.Global;
import com.sf.dlb.constant.CacheConstant;
import com.sf.dlb.constant.ResponseConstant;
import com.sf.dlb.jpa.model.NewRecodInfo;
import com.sf.dlb.jpa.model.UserGradeInfo;
import com.sf.dlb.jpa.model.UserInfo;
import com.sf.dlb.jpa.model.UserNewInfo;
import com.sf.dlb.jpa.repository.NewRecodRepository;
import com.sf.dlb.jpa.repository.UserGradeRepository;
import com.sf.dlb.jpa.repository.UserInfoRepository;
import com.sf.dlb.jpa.repository.UserNewRepository;
import com.sf.dlb.mongo.model.NewList;
import com.sf.dlb.mongo.repository.NewListRepository;
import com.sf.dlb.utils.*;
import com.sf.dlb.vo.NewGetDlbVO;
import com.sf.dlb.vo.ResultVO;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;

/**
 * Created by jing.tan on 2018/5/21.
 */
@Service
public class NewRecodService {
    private static Logger logger = LoggerFactory.getLogger(NewRecodService.class);
    @Autowired
    private NewRecodRepository newRecodRepository;
    @Autowired
    private NewListRepository newListRepository;
    @Autowired
    private UserWalletService userWalletService;
    @Autowired
    private UserNewService userNewService;
    @Autowired
    private UserNewRepository userNewRepository;
    @Autowired
    private UserInfoRepository userInfoRepository;
    @Autowired
    private UserGradeRepository userGradeRepository;
    @Resource
    public Global global;
    @Autowired
    public RedisUtil redisUtil;


    /**
     * 开始阅读
     * @param newRquestBean
     * @return
     */
    public ResultVO startReadNew(NewRquestBean newRquestBean){
        logger.info("startReadNew start newRquestBean={} ",GsonUtils.getInstance().toJson(newRquestBean));
        //是否已读
        String newId=newRquestBean.getNewId();
        String userId=newRquestBean.getUserId();
        NewRecodInfo newRecodInfo= newRecodRepository.findByUserIdAndNewIdAndDelFlag(userId,newId,"0");
        if(null!=newRecodInfo){
            logger.info("startReadNew 此新闻已读 ");
            return ResultVOUtil.success(); //前端要求，不要提示；
        }
        //保存阅读记录
        newRecodInfo=new NewRecodInfo();
        newRecodInfo.setUserId(newRquestBean.getUserId());
        newRecodInfo.setNewId(newId);
        newRecodInfo.setGetState("0");
        NewList newListInfo= newListRepository.findByIdAndDelFlag(newId,"0");
        if(newListInfo!=null){
            newRecodInfo.setClassId(newListInfo.getClassId());
        }
        newRecodInfo.setStartTime(new Date());
        newRecodInfo.setCreateDate(new Date());
        newRecodInfo.setUpdateDate(new Date());
        newRecodRepository.save(newRecodInfo);
        return ResultVOUtil.success();
    }
    /**
     * 结束阅读
     * @param newRquestBean
     * @return
     */
    @Transactional
    public ResultVO endReadNew(NewRquestBean newRquestBean){
        logger.info("endReadNew start newRquestBean={} ",GsonUtils.getInstance().toJson(newRquestBean));
        String newId=newRquestBean.getNewId();
        String userId=newRquestBean.getUserId();
        //判断是否并发访问-redis
        boolean readFlag=isNewsGetDlb(userId,newId);
        if(readFlag){
            logger.info("endReadNew 并发访问 ");
            return ResultVOUtil.error(ResponseConstant.ERROR,"");
        }
        //是否已读
        NewRecodInfo newRecodInfo= newRecodRepository.findByUserIdAndNewIdAndDelFlag(userId,newId,"0");
        if(null==newRecodInfo){
            logger.info("endReadNew 此新闻未读 ");
            return ResultVOUtil.error(ResponseConstant.ERROR,"");//前端要求；
        }
        //如果结束时间已存在，就不再计算
        Date endTimeD=newRecodInfo.getEndTime();
        if(null!=endTimeD){
            logger.info("endReadNew 此新闻已结束阅读 ");
            return ResultVOUtil.error(ResponseConstant.ERROR,"");//前端要求；由于前端是统一处理错误信息；所以建议不要有提示；不然会导致领取dlb的提示弹不出来；重叠了；
        }
        //计算阅读时间
        Date startTime=newRecodInfo.getStartTime();
        Date endTime=new Date();
        long compare=DateUtils.differTimeLong(startTime,endTime)/1000; //秒
        //记录结束阅读时间，状态
        newRecodInfo.setEndTime(endTime);
        newRecodInfo.setReadTimeLong((int)compare);
        newRecodInfo.setGetState("0");
        newRecodInfo.setUpdateDate(new Date());
        newRecodRepository.save(newRecodInfo);
        //判断有效阅读
        NewList newListInfo = newListRepository.findByIdAndDelFlag(newId,"0");
        String slideNumberStr=newRquestBean.getSlideNumber();
        String[] slideNumberStrs=slideNumberStr.split("&");
        int normNumber=Integer.parseInt(slideNumberStrs[0]);//标准
        int realityNumber=Integer.parseInt(slideNumberStrs[1]);//实际
        Integer getDlbTime=newListInfo.getGetDlbTime();
        logger.info("endReadNew getDlb normNumber={},realityNumber={},readTime={}",normNumber,realityNumber,getDlbTime);
        boolean readTimeFlag=compare>=getDlbTime;//阅读时间有效标识(结束时间-开始时间>=有效阅读时间)
        boolean sildeNumberFlag=(realityNumber+global.new_read_slide_number_factor)>=normNumber;//滑动次数有效标识
        logger.info("endReadNew getDlb readTimeFlag={},sildeNumberFlag={}",readTimeFlag,sildeNumberFlag);
        if(readTimeFlag&&sildeNumberFlag){//两个条件都成立，才算有效阅读
            logger.info("endReadNew getDlb userId={},newId={}",userId,newId);
            NewRquestBean newRquestBean1=new NewRquestBean();
            newRquestBean1.setUserId(userId);
            newRquestBean1.setNewId(newId);
            ResultVO resultVO=getDlb(newRquestBean1);
            return resultVO;
        }
        return ResultVOUtil.success();
    }
    /**
     * 领取dlb
     * @return
     */
    @Transactional
    public ResultVO getDlb(NewRquestBean newRquestBean){
        logger.info("getDlb start newRquestBean={} ",GsonUtils.getInstance().toJson(newRquestBean));
        String userId = newRquestBean.getUserId();
        String newId=newRquestBean.getNewId();
        NewRecodInfo newRecodInfo= newRecodRepository.findByUserIdAndNewIdAndDelFlag(userId,newId,"0");
        //是否领取过
        String getDlb=newRecodInfo.getGetState();
        if(StringUtils.isNotBlank(getDlb)&&getDlb.equals("1")){
            logger.info("getDlb 此新闻已领取过dlb ");
            return ResultVOUtil.error(ResponseConstant.ERROR,"");
        }
        //计算此新闻，计算P的值，领取的dlb
        Double currentGetDlb=countGetDlb(userId);
        //更新阅读记录为已领取
        newRecodInfo.setGetState("1");
        newRecodInfo.setGetNumber(currentGetDlb);
        newRecodInfo.setUpdateDate(new Date());
        newRecodRepository.save(newRecodInfo);
        //更新用户钱包
        userWalletService.updateUserWallet(userId,currentGetDlb,ResponseConstant.source_type_reading,ResponseConstant.source_type_reading_value+":newId:"+newId);
        //更新用户新闻
        UserNewInfo userNewInfo =userNewService.updateUserNew(userId,newRecodInfo.getReadTimeLong(),currentGetDlb);
        //封装VO
        NewGetDlbVO newGetDlbVO=new NewGetDlbVO();
        newGetDlbVO.setGetDlb(StringFormatUtils.kill3Decimals(currentGetDlb));
        newGetDlbVO.setGetDlbCount(StringFormatUtils.kill3Decimals(userNewInfo.getHistoryGetdlbCount()));
        newGetDlbVO.setNewId(newId);
        logger.info("getDlb  currentGetDlb={} ,userNewInfo.getHistoryGetdlbCount()={}",currentGetDlb,userNewInfo.getHistoryGetdlbCount());
        return ResultVOUtil.success(newGetDlbVO);
    }
    /**
     * 计算此新闻 领取的dlb
     */
    public Double countGetDlb(String userId){
        logger.info("countGetDlb start userId={} ",userId);
        //1》P=0.5； 配置文件
        double PValue=global.wallet_read_getdlb_yield;
        //2》今天阅读的数量；阅读记录表；userId+日期查；
        int everyDayReadNumerI;
        String currentDateStr=DateUtils.getDate("yyyy-MM-dd");
        Integer everyDayReadNumerO= newRecodRepository.findByEveryDayReadNumber(userId,currentDateStr,"0");
        everyDayReadNumerI=(everyDayReadNumerO==null?0:everyDayReadNumerO);
        //3》会员的等级倍数；等级表；通过等级查
        int readMultiple=1;//普通等级=1*P
        UserInfo userInfo=userInfoRepository.findByUserIdAndDelFlag(userId,"0");
        if(!StringUtils.equals(userInfo.getUserGrade(),"0")){
            UserGradeInfo userGradeInfo=userGradeRepository.findByGradeAndDelFlag(userInfo.getUserGrade(),"0");
            if(null==userGradeInfo){
                readMultiple=1;
            }else{
                readMultiple=userGradeInfo.getMultiple();
            }
            logger.info("countGetDlb readMultiple={}",readMultiple);
        }
        //4》每30天减半；被减半了多少次；多少次，就是多少平方；
        int reduceNumber=0;
        UserNewInfo userNewInfo=userNewRepository.findByUserIdAndDelFlag(userId,"0");
        if(null==userNewInfo){
            logger.info("countGetDlb userNewInfo null==userNewInfo");
            return 0.0;
        }
        String readGetDlbRule=userNewInfo.getReadGetdlbRule();
        if(StringUtils.isNotBlank(readGetDlbRule)){
            String[] readGetDlbRuleSplit=readGetDlbRule.split(",");
            reduceNumber=Integer.parseInt(readGetDlbRuleSplit[0]);
        }
        //计算规则
        logger.info("countGetDlb PValue={},readMultiple={},everyDayReadNumerI={},currentDateStr={},reduceNumber={}",PValue,readMultiple,everyDayReadNumerI,currentDateStr,reduceNumber);
        double countPValue;
        if(readMultiple>1){
//            大于0,购买了等级； 倍数*p
            countPValue=Arith.mul(readMultiple,PValue);
        }else{
//            小于等于0，普通会员；减半**P
            double tempMultiple=2;//每次都是2的倍数
            if(reduceNumber>0){
                countPValue=Arith.mul(PValue,Arith.div(1,StrictMath.pow(tempMultiple,reduceNumber)));
            }else{
                countPValue=PValue;
            }
        }
        double getdlbCount=hanlderReadNumbeReduce(everyDayReadNumerI,countPValue);
        //更新阅读奖励单位-只用于查看或显示
        userNewInfo.setReadGetdlbUnit(getdlbCount);
        userNewInfo.setUpdateDate(new Date());
        userNewRepository.save(userNewInfo);
        logger.info("validGetDlb userNewInfo={}",GsonUtils.getInstance().toJson(userNewInfo));
        return getdlbCount;
    }
    /**
     * 处理阅读数量-递减
     */
    public double hanlderReadNumbeReduce(int readNumber,double unitP){
        logger.info("hanlderReadNumbeReduce readNumber={},unitP={}",readNumber,unitP);
        int reduceReference=global.user_every_reduce_number;//每隔60篇，递减参考值
        double tempMultiple=2;//每次都是2的倍数
        int manyPiece=(readNumber/reduceReference)+1;
        double tempCount;
        if(manyPiece>1){
            //大于0;表示阅读超过60篇；每超过60篇，递减一半
            manyPiece=manyPiece-1;
            logger.info("hanlderReadNumbeReduce manyPiece={}",manyPiece);
            double countUnitP=unitP*Arith.div(1,StrictMath.pow(tempMultiple,manyPiece));//p*(2(n-1)/1), p=unitp,n=manyPiece
            tempCount=countUnitP;
        }else{
            //小于0，表示阅读没有超过60篇
            tempCount=unitP;
        }
        logger.info("hanlderReadNumbeReduce tempCount={}",StringFormatUtils.kill3Decimals(tempCount));
        return tempCount;
    }
    /**
     * 判断新闻是否被读取过
     */
    public boolean isNewsGetDlb(String userId,String newId){
        String key=CacheConstant.USER_CACHE+CacheConstant.USER_READ_CONCURRENT_PREFIX+userId+":"+newId;
        boolean existFlag=redisUtil.hasKey(key);
        if(existFlag){
            return true;
        }else{
            redisUtil.set(key,"1",5);//2秒内不能重复结束阅读
            return false;
        }
    }
}
